package com.ycl.bookstore.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycl.bookstore.DTO.BuyBookDTO;
import com.ycl.bookstore.DTO.UserDTO;
import com.ycl.bookstore.common.Result;
import com.ycl.bookstore.mapper.*;
import com.ycl.bookstore.pojo.*;
import com.ycl.bookstore.service.BooksService;
import com.ycl.bookstore.utils.MyThreadLocal;
import com.ycl.bookstore.utils.RedisIdWorker;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static com.ycl.bookstore.utils.RedisConstants.*;

/**
 *
 */
@Service
public class BooksServiceImpl extends ServiceImpl<BooksMapper, Books>
        implements BooksService {

    //计算书籍总数量
    private Long total;
    //书籍列表
    List<Books> bookList = null;

    @Resource
    private BooksMapper booksMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserOrderMapper userOrderMapper;

    @Resource
    private UserCouponMapper userCouponMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private BalanceMapper balanceMapper;

    @Resource
    private UserBookMapper userBookMapper;

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    @Transactional
    public Result getListByPage(String title, String author, Long pageNo, Long pageSize) {
        //如果title或者author就进行模糊查询
        if (title != null || author != null) {
            LambdaQueryWrapper<Books> wrapper = new LambdaQueryWrapper<>();
            wrapper.like(title != null, Books::getTitle, title);
            wrapper.like(author != null, Books::getAuthor, author);
            Page<Books> page = new Page<>(pageNo, pageSize);
            Page<Books> booksPage = booksMapper.selectPage(page, wrapper);
            total = booksPage.getTotal();
            bookList = booksPage.getRecords();
        } else {
            //获得redis书籍的总数量
            total = stringRedisTemplate.opsForZSet().size(BOOK_LIST_KEY);
            //redis不存在就创建书籍
            if (total <= 0) {
                //将书籍存入redis中
                creatBookListByRedis();
            }
            //存在书籍
            bookList = getBookList(pageNo, pageSize);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("bookList", bookList);
        return Result.success(map);
    }


    /**
     * 得到书籍的详细内容
     *
     * @param id
     * @return
     */
    @Override
    public Result getBookById(Long id) {
        //从redis中查询 减少数据库的压力
        Set<String> set = stringRedisTemplate.opsForZSet().rangeByScore(BOOK_LIST_KEY, id, id);
        String jsonBook = null;
        for (String s : set) {
            jsonBook = s;
        }
        //将json对象转为书籍对象
        Books book = JSONUtil.toBean(jsonBook, Books.class);
        Map<String, Object> map = new HashMap<>();
        map.put("book", book);
        return Result.success(map);
    }

    @Override
    @Transactional
    public Result buyBook(BuyBookDTO buyBookDTO) {
        // 查询用户所购买的信息
        Books books = booksMapper.selectById(buyBookDTO.getId());
        // 判断书籍的库存是否充足
        Integer quantity = books.getQuantity();
        if (quantity < buyBookDTO.getNum()) {
            // 库存不足
            return Result.fail("库存不足,商家正在补货中");
        }
        // 查询书籍的价格
        BigDecimal price = books.getPrice();
        // 计算用户应该支付的金额
        BigDecimal sumPrice = price.multiply(new BigDecimal(buyBookDTO.getNum()));
        // 判断用户是否使用了优惠劵(0 表示未使用优惠劵  1表示使用了优惠劵)
        int isUseCoupon = 0;
        // 判断用户是否使用了优惠卷
        if (buyBookDTO.getSelectedCoupon() != null && sumPrice.compareTo(buyBookDTO.getSelectedCoupon().getMinimumAmount()) >= 0) { // 用户使用优惠劵应满足优惠劵的要求
            isUseCoupon = 1;
            sumPrice = sumPrice.subtract(buyBookDTO.getSelectedCoupon().getDiscountAmount());
            // 修改用户优惠劵信息
            UpdateWrapper<UserCoupon> userCouponWrapper = new UpdateWrapper<>();
            userCouponWrapper.eq("coupon_id", buyBookDTO.getId())
                    .eq("coupon_type", buyBookDTO.getSelectedCoupon().getCouponType())
                    .set("usage_status", "已使用")
                    .set("usage_date", LocalDateTime.now());
            userCouponMapper.update(null, userCouponWrapper);
            // 删除redis中的用户优惠劵缓存
            String hashKey = buyBookDTO.getSelectedCoupon().getCouponId() + "-" + buyBookDTO.getSelectedCoupon().getCouponType();
            // 获取用户id
            Long userId = MyThreadLocal.getUser().getId();
            Long deleteNum = stringRedisTemplate.opsForHash().delete(USER_COUPON_KEY + userId, hashKey);
        }
        // 获取用户的id
        Long userId = MyThreadLocal.getUser().getId();
        // 获取key
        String key = USER_BALANCE_KEY;
        // 从redis查询用户的余额查看用户的余额
        BigDecimal balance = null;
        Object o = stringRedisTemplate.opsForHash().get(key, String.valueOf(userId));
        if (o == null) {
            // 表示redis中是空的
            Balance userBalance = balanceMapper.selectById(userId);
            balance = userBalance.getBalance();
        } else {
            balance = new BigDecimal((String) o);
        }
        // 判断用户的金额是否充足
        int res = balance.compareTo(sumPrice);
        if (res < 1) {
            // 金额不足
            return Result.fail("购买失败,金额不足,请充值金额");
        }
        // 余额充足(修改用户的数据库金额)
        balance = balance.subtract(sumPrice);
        UpdateWrapper<Balance> balanceWrapper = new UpdateWrapper<>();
        balanceWrapper.eq("user_id", userId).set("balance", balance);
        balanceMapper.update(null, balanceWrapper);
        // 删除redis中的缓存
        stringRedisTemplate.opsForHash().delete(key, String.valueOf(userId));
        // 查询书籍的库存
        // 修改用户购买的书籍库存
        UpdateWrapper<Books> bookWrapper = new UpdateWrapper<>();
        // update books set quantity=quantity-#{num} where id=#{id} and quantity>=#{num}
        bookWrapper.eq("id", buyBookDTO.getId())
                .ge("quantity", buyBookDTO.getNum())
                .set("quantity", quantity - buyBookDTO.getNum());
        int count = booksMapper.update(null, bookWrapper);
        if (count < 1) {
            return Result.fail("购买失败,库存不足");
        }
        // 删除redis中的书籍缓存
        stringRedisTemplate.delete(BOOK_LIST_KEY);
        // 创建用户信息
        UserOrder userOrder = createUserOrder(isUseCoupon, sumPrice, buyBookDTO.getNum(), books.getTitle());
        // 向数据库中插入用户订单
        userOrderMapper.insert(userOrder);
        // 将用户订单信息存入redis中
        String userOrderJson = JSONUtil.toJsonStr(userOrder);
        stringRedisTemplate.opsForZSet().add(USER_ORDER_KEY + userId, userOrderJson, userOrder.getOrderId());
        return Result.success(sumPrice);
    }

    /**
     * 我的书籍管理
     *
     * @param title
     * @return
     */
    @Override
    public Result getMyBook(String title) {
        Long userId = MyThreadLocal.getUser().getId();
        // 从redis中取出用户书籍
        String key = USER_BOOK_LIST + userId;
        // 插卡redis是否有缓存
        Boolean res = stringRedisTemplate.hasKey(key);
        if(!res){ // 不存在缓存
            // 数据库中查询数据
            LambdaQueryWrapper<UserBook> wrapper=new LambdaQueryWrapper<>();
            wrapper.eq(UserBook::getUserId,userId);
            List<UserBook> userBooks = userBookMapper.selectList(wrapper);
            for (UserBook userBook : userBooks) {
                String jsonStr = JSONUtil.toJsonStr(userBook);
                stringRedisTemplate.opsForHash().put(key,userBook.getBookId()+"",jsonStr);
            }
            return Result.success(userBooks);
        }
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(key);
        List<UserBook> data=new LinkedList<>();
        Set<Object> set = map.keySet();
        for (Object userBookKey : set) {
            UserBook bean = JSONUtil.toBean((String) map.get(userBookKey), UserBook.class);
            data.add(bean);
        }
        return Result.success(data);
    }

    @Override
    public Result createUserBook(Long id, Long num) {
        Long userId = MyThreadLocal.getUser().getId();
        // 判断数据库是否存在书籍
        LambdaQueryWrapper<UserBook> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(UserBook::getUserId,userId)
                .eq(UserBook::getBookId,id);
        UserBook userBook = userBookMapper.selectOne(queryWrapper);
        if (userBook != null) { // 表示用户之前购买过该书籍 只需要修改数量
            UpdateWrapper<UserBook> wrapper = new UpdateWrapper<>();
            wrapper.set("number", userBook.getNumber() + num)
                    .eq("book_id", id);
            userBookMapper.update(null, wrapper);
            // 删除redis中的缓存
            stringRedisTemplate.delete(USER_BOOK_LIST + userId);
            return Result.success();
        }
        // 用户第一次购买这个书籍时
        // 从数据库查询信息
        Books book = booksMapper.selectById(id);
        // 当发送这个请求的时候  表示用户购买书籍成功
        userBook = new UserBook();
        userBook.setBookId(id);
        userBook.setTitle(book.getTitle());
        userBook.setNumber(num);
        userBook.setAuthor(book.getAuthor());
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        userBook.setUserId(userId);
        userBook.setPurchaseDate(now);
        userBook.setCreateDate(now);
        userBook.setUpdateDate(now);
        // 存入数据库中
        int count = userBookMapper.insert(userBook);
        if (count < 1) {
            return Result.fail("购买失败");
        }
        String jsonStr = JSONUtil.toJsonStr(userBook);
        // 存入redis中
        stringRedisTemplate.opsForHash().put(USER_BOOK_LIST + userId, String.valueOf(id), jsonStr);
        return Result.success();
    }

    public List<Books> getBookList(Long pageNo, Long pageSize) {
        Long start = (pageNo - 1) * pageSize;
        Long edd = start + pageSize - 1;
        //分页查询
        Set<String> bookSet = stringRedisTemplate.opsForZSet().range(BOOK_LIST_KEY, start, edd);
        List<Books> bookList = new ArrayList<>();
        // 将书籍对象转化json对象存入redis中
        for (String book : bookSet) {
            bookList.add(JSONUtil.toBean(book, Books.class));
        }
        return bookList;
    }

    public void creatBookListByRedis() {
        //查询所有书籍
        List<Books> books = booksMapper.selectList(null);
        total = Long.valueOf(books.size());
        for (Books book : books) {
            stringRedisTemplate.opsForZSet().add(BOOK_LIST_KEY, JSONUtil.toJsonStr(book), book.getId());
        }
    }

    /**
     * 创建用户订单
     */
    public UserOrder createUserOrder(int isUseCoupon, BigDecimal sumPrice, Long num, String bookTitle) {
        // 获取当前用户
        UserDTO user = MyThreadLocal.getUser();
        // 创建用户订单对象
        UserOrder order = new UserOrder();
        // 生成订单号
        long userOrderId = new RedisIdWorker(stringRedisTemplate).nextId(USER_ORDER_KEY);
        order.setOrderId(userOrderId);
        order.setUserId(user.getId());
        order.setNickName(user.getNickName());
        order.setIsCouponUsed(isUseCoupon);
        order.setOrderAmount(sumPrice);
        LocalDateTime now = LocalDateTime.now();
        // 购买的书籍标题
        order.setBookTitle(bookTitle);
        // 购买书籍的数量
        order.setBookNumber(num);
        order.setOrderDate(now);
        // 获取今天的日期
        order.setCreatedAt(now);
        order.setStatus(0);
        return order;
    }
}





